package com.ft.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ft.dao.LostarticleDao;
import com.ft.dao.SeekarticleDao;
import com.ft.domain.Buyorder;
import com.ft.domain.Lostarticle;
import com.ft.domain.Seekarticle;
import com.ft.service.ILostarticleService;
import com.ft.service.ISeekarticleService;
import com.ft.utils.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author com/ft
 * @since 2022-08-24
 */
@Service
public class SeekarticleServiceImpl extends ServiceImpl<SeekarticleDao, Seekarticle> implements ISeekarticleService {
    @Autowired
    private SeekarticleDao seekarticleDao;
    @Autowired
    RedisTemplate redisTemplate;
    /**
     * 创建失物招领订单
     * @param order 订单对象
     * @return 受影响的行数
     */
    @Override
    public int createSeekarticle(Seekarticle order) throws IllegalAccessException {

        /**
         * 先存redis,在存数据库，最后存数据库成功后进行校验，保证数据库和redis里都有数据并且一致
         *  1.封装订单编号，存入buyorderZset所有订单集合中
         *  oldBuyOrderId: 获取添加Zset前的个数
         *  id ：订单id
         */
        //无偿的所有订单数据个数
        Long oldBuyOrderId = redisTemplate.opsForZSet ().zCard ("seekarticleId");
        //有偿的zset集合所有订单个数
        Long oldSeekarticlePaidId = redisTemplate.opsForZSet ().zCard ("seekarticlePaidId");
        String id = String.valueOf(order.getId());
        //先判断订单是否有有偿的
        Integer paid = order.getPaid ();
        Boolean T ;//控制是否是有偿的变量
        //无偿
        if (paid == 0) {
            redisTemplate.opsForZSet().add("seekarticleId",id,1);
            T = false;
        }else {
            //有偿的
            redisTemplate.opsForZSet().add("seekarticlePaidId",id,0);
            T = true;
        }
        /**
         *  2.将订单号存入用户的未付款的set里
         * 格式：订单类型 : 用户id : nopay
         * orderKey :封装的key
         * oldlistsize: 添加前的用户未付款set集合长度
         */
        int userid = order.getIssueUser ();
        String orderKey = "seekarticle:"+userid+":nopay";
        Long oldlistsize = redisTemplate.opsForSet().size (orderKey);
        if(T){
            redisTemplate.boundSetOps(orderKey).add(id);
        }
        /**
         *  3.封装订单信息，存入Hsah里
         *  格式：订单类型 : 用户id : 订单号
         *  orderKey1：封装hash的key值
         *  stringObjectMap：得到对象属性的map集合
         */
        String orderKey1 = "seekarticle:"+order.getId ();
        Map<String, Object> stringObjectMap = ObjectUtils.objectToMap (order);
        redisTemplate.opsForHash ().putAll (orderKey1, stringObjectMap);
        /**
         * 4.将数据存入数据库
         */
        int lostarticle = seekarticleDao.createSeekarticle (order);
        /**
         * 数据校验，保证数据一致性
         * newBuyOrderId：获取添加后的所有订单的Zset个数
         * newlistsize:添加后的用户未付款list集合长度
         * hashOrderStr：获取存入redis的数据
         * hashOrderSize ：订单表所有字段的和
         */
        if (lostarticle == 1 ){
            while (true){
                Long newlistsize = redisTemplate.opsForSet ().size (orderKey);
                Long  hashOrderSize = redisTemplate.opsForHash().size (orderKey1);
                if(T){
                    //有偿的zset集合所有订单个数
                    Long newseekarticlePaidId = redisTemplate.opsForZSet ().zCard ("seekarticlePaidId");
                    //结束条件
                    if(newseekarticlePaidId > oldSeekarticlePaidId & newlistsize > oldlistsize & hashOrderSize == Seekarticle.total){
                        break;
                    }
                    //对存入订单id进行校验
                    if(newseekarticlePaidId <= oldSeekarticlePaidId){
                        redisTemplate.opsForZSet().add("seekarticlePaidId",id,0);
                        continue;
                    }
                    //对存入用户未付款set集合进行校验
                    if (newlistsize <= oldlistsize){
                        redisTemplate.boundSetOps(orderKey).add(id);
                        continue;
                    }
                }else {
                    Long newBuyOrderId = redisTemplate.opsForZSet().zCard("seekarticleId");
                    //结束条件
                    if(newBuyOrderId > oldBuyOrderId  & hashOrderSize == Seekarticle.total){
                        break;
                    }
                    //对存入订单id进行校验
                    if(newBuyOrderId <= oldBuyOrderId){
                        redisTemplate.opsForZSet().add("seekarticleId",id,1);
                        continue;
                    }
                }
                //对hash订单表进行校验
                if(hashOrderSize != Seekarticle.total){
                    //移除key
                    redisTemplate.delete (orderKey1);
                    //重新添加
                    Map<String, Object> stringObjectMap1 = ObjectUtils.objectToMap (order);
                    Set mapkey1 = stringObjectMap.keySet ();
                    for(Object key : mapkey1){
                        redisTemplate.opsForHash().put(orderKey1,key,stringObjectMap.get (key));
                    }
                }
            }
            //同步订单创建时间
            redisTemplate.opsForHash().delete(orderKey1,"createTime");
            String time = seekarticleDao.getcreateTime(order.getId ());
            redisTemplate.opsForHash().put(orderKey1,"createTime",time);
            return 1;
        }else {
            //存入数据库失败，删除缓存数据
            if(T){
                redisTemplate.boundZSetOps ("seekarticlePaidId").remove (id);
            }else {
                redisTemplate.boundZSetOps ("seekarticleId").remove (id);
            }
            redisTemplate.boundSetOps(orderKey).remove (id);
            redisTemplate.delete (orderKey1);
            return 0;
        }
    }

    /**
     * 查询订单的所有信息
     * @param id 订单id
     * @return
     */
    @Override
    public Seekarticle selectSeekarticle(Long id) {
        Seekarticle lostarticle = seekarticleDao.selectSeekarticle (id);
        return lostarticle;
    }

    /**
     * 查询用于支付订单的信息
     * @param id 订单id
     * @return
     */
    @Override
    public Seekarticle selectSeekarticleToPay(Long id) {
        Seekarticle seekarticle = seekarticleDao.selectSeekarticleToPay (id);
        return seekarticle;
    }

    /**
     * 付款后，修改订单状态
     * @return 返回受影响的结果
     */
    @Override
    public int updataOrder(int state,String id,int userid) {
        int i = seekarticleDao.updataOrder (state,id);
        String key ="seekarticle:"+id;
        if(i == 1){
            //移除用户未支付set里的订单数据
            redisTemplate.opsForSet ().remove ("seekarticle:"+userid+":nopay",id);
            //向用户已支付set里添加数据
            redisTemplate.opsForSet ().add ("seekarticle:"+userid+":okpay",id);
            //移除有偿集合里的id
            redisTemplate.boundZSetOps ("seekarticlePaidId").remove (id);
            //添加到所有订单中
            redisTemplate.opsForZSet().add("seekarticleId",id,1);
            //修改订单hash表state状态
            redisTemplate.opsForHash().delete(key,state);
            redisTemplate.opsForHash().put(key,"state",1);
            //更新订单时间
            redisTemplate.opsForHash().delete(key,"updateTime");
            String time = seekarticleDao.getupdateTime(Long.valueOf (id));
            redisTemplate.opsForHash().put(key,"updateTime",time);
            return 1;
        }else {
            return 0;
        }
    }
    /**
     * 失物招领分页获取订单数据
     * @param page
     * @return
     */
    @Override
    public List getOrder(int type,int page) {
        //同类型的集合数据
        List resulttype = new ArrayList ();
        //返回的数据
        List result = new ArrayList ();
        //获取所有订单数据
        Set lostarticleId = redisTemplate.opsForZSet ().reverseRangeByScore("seekarticleId", 1, 999);
        //遍历set获取同类型的数据
        for(Object le : lostarticleId){
            Map entries = redisTemplate.opsForHash ().entries ("seekarticle:" + le);
            int T = (int) entries.get ("type");
            if(T == type + 1){
                //对id进行处理
                Object id = entries.get ("id");
                entries.put ("id",""+id);
                resulttype.add (entries);
            }
        }
        //如果数据小于5的情况
        if(resulttype.size() < 5){
            for(int i = 0;i < resulttype.size(); i++){
                //将map转成对象
                result.add (JSONObject.parseObject(JSONObject.toJSONString(resulttype.get(i)), Seekarticle.class));
            }
            return result;
        }else {
            //每次返回5个数据，total：获取数据结束的位置
            int total = 0;
            //每次获取数据循环开始的位置
            int num = page * 5;
            if(page == 0){
                total = 5;
            }else {
                total = (page+1) * 5;
            }
            for (;num < total & num < resulttype.size(); num++){
                Seekarticle lostarticle = JSONObject.parseObject (JSONObject.toJSONString (resulttype.get (num)), Seekarticle.class);
                result.add (lostarticle);
            }
            return result;
        }
    }

    /**
     * 搜索内容
     * @param content 搜索的数据
     * @return
     */
    @Override
    public List search(String content,int type,int page) {
        //返回结果集合
        List result = new ArrayList ();
        //获取订单数据
        Set buyorderId = redisTemplate.opsForZSet ().reverseRangeByScore("seekarticleId", 1, 999);
        //遍历集合取出数据
        for(Object key : buyorderId){
            Map entries = redisTemplate.opsForHash ().entries ("seekarticle:" + key);
            String ct = (String) entries.get ("content");
            Integer type1 = (Integer) entries.get ("type");
            if(type1 == type+1 & ct.contains (content) ){
                //对id进行处理
                Object id = entries.get ("id");
                entries.put ("id",""+id);
                result.add(entries);
            }
        }
        System.out.println("result的大小"+result.size());
        //数据小于5的情况
        if(result.size() < 5){
            return result;
        }else {
            List ids = new ArrayList();
            //每次返回5个数据，total：获取数据结束的位置
            int total = 0;
            //每次获取数据循环开始的位置
            int num = page * 5;
            if(page == 0){
                total = 5;
            }else {
                total = (page+1) * 5;
            }
            for(;num < total & num < result.size (); num++){
                ids.add (result.get(num));
            }
            return ids;
        }
    }
}
